﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Windows.Forms;
using System.IO;
using DevExpress.XtraEditors;
using DevExpress.XtraTab;
using System.Data;

namespace Future.FormBase
{
    /// <summary>
    /// 加载模块管理类(Load Module Manager)
    /// </summary>
    public class ModuleLoader
    {
        /// <summary>
        /// 模块文件名(DLL文件外)
        /// </summary>
        private string _ModuleFileName;

        /// <summary>
        /// 如果加载了模块,就返回该模块的主窗体对象
        /// </summary>
        private frmModuleBase _ModuleMainForm = null;

        /// <summary>
        /// 模块所在的程序集
        /// </summary>
        private Assembly _ModuleAssembly;

        public static readonly string MODULE_FILTER = "FutureCRM系统管理系统 Modules|*.dll";

        /// <summary>
        /// 模块文件所在路径
        /// </summary>
        public static readonly string MODULE_PATH = Application.StartupPath;

        public ModuleLoader()
        {
            //
        }


        /// <summary>
        /// 模块所在的程序集
        /// </summary>
        public Assembly ModuleAssembly
        {
            get { return _ModuleAssembly; }
        }

        /// <summary>
        /// 返回AssemblyModuleEntry，自定义模块特性的ModuleName
        /// </summary>
        /// <returns></returns>
        public string GetCurrentModuleName()
        {
            return ModuleLoader.GetModuleEntry(_ModuleAssembly).ModuleName;
        }

        /// <summary>
        /// 模块主窗体
        /// </summary>
        public frmModuleBase ModuleMainForm
        {
            get { return _ModuleMainForm; }
        }

        /// <summary>
        /// 加载模块的菜单
        /// </summary>
        /// <param name="menuStrip">程序主窗体的菜单</param>
        public void LoadMenu(MenuStrip moduleMenus)
        {
            if ((_ModuleMainForm != null) && (_ModuleMainForm.GetModuleMenu() != null))
            {
                //转移菜单
                int startIndex = moduleMenus.Items.Count == 0 ? 0 : moduleMenus.Items.Count - 1;
                moduleMenus.Items.Insert(startIndex, _ModuleMainForm.GetModuleMenu().Items[0]);
            }
        }

        /// <summary>
        /// 加载模块方法
        /// </summary>
        /// <param name="moduleInfo">模块信息</param>
        /// <returns></returns>
        public bool LoadModule(ModuleInfo moduleInfo)
        {
            _ModuleFileName = moduleInfo.ModuleFile;
            _ModuleAssembly = moduleInfo.ModuleAssembly;
            string entry = ModuleLoader.GetModuleEntryNameSpace(_ModuleAssembly);
            if (string.Empty == entry) return false;

            Form frm = (Form)_ModuleAssembly.CreateInstance(entry);
            _ModuleMainForm = null;

            if (frm is IModuleBase)
                _ModuleMainForm = (frmModuleBase)frm;
            return _ModuleMainForm != null;
        }

        public IList<ModuleInfo> GetModuleList()
        {
            try
            {
                string[] files = null;//模块文件(*.dll)
                IList<ModuleInfo> list = new List<ModuleInfo>();

                if (Directory.Exists(MODULE_PATH))
                    files = Directory.GetFiles(MODULE_PATH);

                foreach (string mod in files)
                {
                    Assembly asm = null;
                    try
                    {
                        asm = Assembly.LoadFile(mod);
                    }
                    catch { continue; }

                    ModuleID id = GetModuleID(asm);
                    string name = GetCurrentModuleName();
                    if (id != ModuleID.None)
                    {
                        ModuleInfo m = new ModuleInfo(asm, id, name, mod);
                        list.Add(m);
                    }
                }
                SortModule(list);

                return list;
            }
            catch (Exception ex)
            {
                Common.Msg.ShowException(ex);
                return null;
            }
        }
        /// <summary>
        ///  获取程序集自定义特性。是否用户自定义模块由AssemblyModuleEntry特性确定。
        /// </summary>
        /// <returns></returns>
        public AssemblyModuleEntry GetModuleEntry()
        {
            return ModuleLoader.GetModuleEntry(_ModuleAssembly);
        }

        /// <summary>
        /// 判断加载的文件是否模块文件，因目录下可能有不同类别的DLL文件。
        /// 判断DLL为模块的条件是检查Assembly特性。
        /// </summary>
        public bool IsModuleFile(string moduleFile)
        {
            try
            {
                Assembly asm = Assembly.LoadFile(moduleFile);
                return (ModuleLoader.GetModuleID(asm) != ModuleID.None);
            }
            catch { return false; }
        }

        /// <summary>
        /// 每一个模块对应一个XtraTabPage,然后將模块主窗体的Panel容器放置在XtraTabPage内。
        /// 因此，所有加载的模块主窗体的Panel容器都嵌套在主窗体的XtraTabControl内。
        /// </summary>
        public void LoadGUI(XtraTabControl mainTabControl)
        {
            try
            {
                IModuleBase moduleBase = _ModuleMainForm as IModuleBase;

                Control container = moduleBase.GetContainer();//模块主窗体的Panel容器
                if (null != container)
                {
                    container.Dock = DockStyle.Fill;
                    XtraTabPage page = new XtraTabPage();
                    page.Tag = _ModuleMainForm;
                    page.Text = this.GetCurrentModuleName();
                    page.Controls.Add(container);
                    mainTabControl.TabPages.Add(page);
                }
            }
            catch (Exception ex)
            {
                Common.Msg.ShowException(ex);
            }
        }

        /// <summary>
        /// 模块排序
        /// </summary>
        /// <param name="list">模块集合</param>
        public void SortModule(IList<ModuleInfo> list)
        {
            int i, j;
            ModuleInfo temp;
            bool done = false;
            j = 1;
            while ((j < list.Count) && (!done))
            {
                done = true;
                for (i = 0; i < list.Count - j; i++)
                {
                    if ((list[i] as ModuleInfo).ModuleID > (list[i + 1] as ModuleInfo).ModuleID)
                    {
                        done = false;
                        temp = list[i];
                        list[i] = list[i + 1];
                        list[i + 1] = temp;
                    }
                }
            }

        }

        #region 类公共表态方法
        public static ToolStripItem GetMenuItem(ToolStrip mainMenu, string menuName)
        {
            ToolStripItem[] items = mainMenu.Items.Find(menuName, true);
            return (items.Length > 0 && items[0] is ToolStripItem) ? (ToolStripItem)items[0] : null;
        }


        /// <summary>
        /// 获取程序集自定义属性,是否用户自定义模块由AssemblyModuleEntry特性确定。
        /// </summary>
        /// <param name="asm"></param>
        /// <returns></returns>
        public static AssemblyModuleEntry GetModuleEntry(Assembly asm)
        {
            AssemblyModuleEntry temp = new AssemblyModuleEntry(ModuleID.None, "", "");
            if (asm == null) return temp;

            object[] list = asm.GetCustomAttributes(typeof(AssemblyModuleEntry), false);

            return list.Length > 0 ? (AssemblyModuleEntry)list[0] : temp;
        }
        /// <summary>
        /// 获取模块主窗体名字空间
        /// </summary>
        /// <param name="asm"></param>
        /// <returns></returns>
        public static string GetModuleEntryNameSpace(Assembly asm)
        {
            return GetModuleEntry(asm).ModuleEntryNameSpace;
        }
        /// <summary>
        /// 获取模块编号
        /// </summary>
        /// <param name="asm"></param>
        /// <returns></returns>
        public static ModuleID GetModuleID(Assembly asm)
        {
            return GetModuleEntry(asm).ModuleID;
        }
        #endregion

        public bool CanAccessModule(DataTable userPermissions)
        {
            MenuStrip mainMenu = _ModuleMainForm.GetModuleMenu();
            DataRow[] rows = userPermissions.Select(string.Format("AuthorityID='{0}'", mainMenu.Items[0].Name));
            return rows != null && rows.Length > 0;
        }

        public void ClearAssemble()
        {
            _ModuleAssembly = null;
            _ModuleMainForm = null;
        }
    }
}
